package com.distribution.system.manager.channel.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.distribution.common.exception.ServiceException;
import com.distribution.common.utils.StringUtils;
import com.distribution.system.domain.bo.*;
import com.distribution.system.domain.dto.ChoosePhoneDTO;
import com.distribution.system.domain.dto.SendCodeDTO;
import com.distribution.system.domain.entity.AddressChannel;
import com.distribution.system.domain.entity.CmccDaOrder;
import com.distribution.system.domain.entity.CmccDaProduct;
import com.distribution.system.domain.entity.CmccDaUpChannelInfo;
import com.distribution.system.domain.req.ReqResult;
import com.distribution.system.manager.channel.AbstractChannel;
import com.distribution.system.manager.channel.channelInfo.enums.SanJianKeChannelEnum;
import com.distribution.system.service.AddressChannelService;
import com.distribution.system.utils.MD5Util;
import com.distribution.system.utils.http.HttpRequestUtils;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.distribution.system.utils.DictionarySortUtil.dictSort;

/**
 * @author Liping Huo
 * @date 2023/5/23 1:05
 */
@Slf4j
public class SanJianKeChannel extends AbstractChannel {
    private static final Logger sjkOrderSearchLog = LoggerFactory.getLogger("sjkOrderSearchLog");

    public SanJianKeChannel(CmccDaUpChannelInfoBO cmccDaUpChannelInfoBO) {
        super(cmccDaUpChannelInfoBO);
    }

    @Override
    public AddressInfoBo getChannelAddressInfo(AddressNameBo addressNameBo, AddressChannelService addressChannelService) {
        return null;
    }

    @Override
    public String configPlaceOrderRequestParams(CmccDaOrder cmccDaOrder, CmccDaProduct cmccDaProduct, AddressInfoBo addressInfoBo) {
        log.info("配置三剑客下单接口参数...");
        AddressChannel addressInfo = addressInfoBo.getAddressInfo();
        AddressChannel attributeInfo = addressInfoBo.getAttributeInfo();
        // 生成订单号
        orderId = "SJK" + DateUtil.format(DateUtil.date(), "yyyyMMdd") + IdUtil.getSnowflake(1, 1).nextIdStr().substring(8,18);
        HashMap<String, Object> map = new HashMap<>(1 << 4);
        //配置请求参数
        map.put("partnerId", interfaceParamsMap.get(SanJianKeChannelEnum.APP_ID.getName()));
        map.put("cardType", cmccDaOrder.getProductParam());
        map.put("provinceName", attributeInfo.getProvinceName());
        map.put("cityName", attributeInfo.getCityName());
        map.put("number", cmccDaOrder.getChoosePhone() == null ? "" : cmccDaOrder.getChoosePhone());
        map.put("certName", cmccDaOrder.getCustomerName());
        map.put("certNo", cmccDaOrder.getCustomerCertNo());
        map.put("postProvinceName", addressInfo.getProvinceName());
        map.put("postCityName", addressInfo.getCityName());
        map.put("postDistrictName", addressInfo.getDistrictName());
        map.put("postAddr", addressInfo.getProvinceName() + addressInfo.getCityName() + addressInfo.getDistrictName() + cmccDaOrder.getAddressStreet());
        map.put("contactNum", cmccDaOrder.getCustomerPhone());

        /*map.put("safe_code", cmccDaOrder.getCode() == null ? "" : cmccDaOrder.getCode());
        map.put("uniqsn", cmccDaOrder.getPhoneUuid() == null ? "" : cmccDaOrder.getPhoneUuid());
        //这里不知道为什么自动注入得到的redis对象为null，所以反射调用
        RedisCache redisCache = SpringUtils.getBean(RedisCache.class);
        //通过redis缓存查询number对应的check_code
        Map<String, Object> numberCheckMap = redisCache.getCacheMap("numberCheckMap");
        if (!numberCheckMap.isEmpty()) {
            log.info("redis的存值" + numberCheckMap.get(cmccDaOrder.getChoosePhone()));
            map.put("check_code", numberCheckMap.get(cmccDaOrder.getChoosePhone()) == null ? "" : numberCheckMap.get(cmccDaOrder.getChoosePhone()));
        }else {
            map.put("check_code", "");
        }*/
        map.put("safe_code", "1".equals(cmccDaProduct.getCodeFlag()) ? (cmccDaOrder.getCode() == null ? "" : cmccDaOrder.getCode()) : "");
        map.put("uniqsn", "");
        map.put("check_code", "");
        // 如果选号
        if ("1".equals(cmccDaProduct.getSelectNumberFlag())){
            map.put("uniqsn", cmccDaOrder.getPhoneUuid() == null ? "" : cmccDaOrder.getPhoneUuid());
            map.put("check_code", getRedisNumberCheck(cmccDaOrder.getChoosePhone(), cmccDaOrder.getPhoneUuid()));
        }
        String sign = getSign(map, interfaceParamsMap.get(SanJianKeChannelEnum.APP_KEY.getName()));
        map.put("sign", sign);
        return new JSONObject(map).toString();
    }

    @Override
    public String sendPlaceOrderRequest(String requestJsonStr) {
        return HttpRequestUtils.sendPost(interfaceUrlsMap.get(SanJianKeChannelEnum.PLACE_ORDER.getName()), requestJsonStr);
    }

    @Override
    public ReqResult parsePlaceOrderResponseStr(JSONObject responseJsonObject) {
        //响应
        if (!"0000".equals(responseJsonObject.getString("result"))) {// 失败
            return ReqResult.error(responseJsonObject.getString("info"));
        } else {
            JSONObject data = responseJsonObject.getJSONObject("data");
            UnOrderResultBo unOrderResultBo = new UnOrderResultBo();
            unOrderResultBo.setOrderId(orderId);
            unOrderResultBo.setChannelOrderNo(data.getString("orderId"));
            return ReqResult.success(responseJsonObject.getString("info"), unOrderResultBo);
        }
    }

    @Override
    public String configChoosePhoneRequestParams(ChoosePhoneDTO choosePhoneDTO, CmccDaProduct cmccDaProduct, AddressInfoBo addressInfoBo) {
        log.info("请求三剑客选择号码接口...");
        HashMap<String, Object> map = new HashMap<>(1 << 2);
        map.put("partnerId", interfaceParamsMap.get(SanJianKeChannelEnum.APP_ID.getName()));
        map.put("cardType", cmccDaProduct.getProductParam());
        map.put("provinceName", addressInfoBo.getAttributeInfo().getProvinceName());
        map.put("cityName", addressInfoBo.getAttributeInfo().getCityName());
        map.put("searchValue",StringUtils.isBlank(choosePhoneDTO.getKeywords()) ? "" : choosePhoneDTO.getKeywords());
        map.put("pageNo", choosePhoneDTO.getPage());
        // 特殊卡需要传递的参数
        map.put("postProvinceName", addressInfoBo.getAddressInfo().getProvinceName());
        map.put("postCityName", addressInfoBo.getAddressInfo().getCityName());
        map.put("postDistrictName", addressInfoBo.getAddressInfo().getDistrictName());
        map.put("postAddr", choosePhoneDTO.getAddressStreet());
        map.put("certName", choosePhoneDTO.getCertName());
        map.put("certNo", choosePhoneDTO.getCertNum());
        map.put("contactNum", choosePhoneDTO.getCustomerPhone());
        map.put("safe_code", "1".equals(cmccDaProduct.getCodeFlag()) ? choosePhoneDTO.getSmsCode() : "");
        String sign = getSign(map, interfaceParamsMap.get(SanJianKeChannelEnum.APP_KEY.getName()));
        map.put("sign", sign);
        return new JSONObject(map).toString();
    }

    @Override
    public String sendChoosePhoneRequest(String requestJsonStr) {
        return HttpRequestUtils.sendPost(interfaceUrlsMap.get(SanJianKeChannelEnum.CHOOSE_PHONE.getName()), requestJsonStr);
    }

    @Override
    public ReqResult parseChoosePhoneResponseStr(JSONObject responseJsonObject) {
        String msg = responseJsonObject.getString("info");
        if (!"0000".equals(responseJsonObject.getString("result"))) {
            return ReqResult.error(msg);
        } else {
            JSONObject data = responseJsonObject.getJSONObject("data");
            JSONArray phoneNumberArray = data.getJSONArray("numArray");
            ChoosePhoneResultBO choosePhoneResultBO = new ChoosePhoneResultBO();
            List<String> numArray = new ArrayList<>();
            phoneNumberArray.forEach(f -> {
                String phoneNum = String.valueOf(f);
                if (!StringUtils.isEmpty(phoneNum)) numArray.add(phoneNum);
            });
            choosePhoneResultBO.setNumArray(numArray);
            String uuid = data.getString("uniqsn");
            choosePhoneResultBO.setUuid(uuid);
            //通过redis缓存将Key(phoneNumber + uuid)与Value(check_code)绑定
            redisCacheNumberCheckMap(numArray,uuid, data.getJSONArray("checkList"));
            return ReqResult.success(choosePhoneResultBO);
        }
    }

    @Override
    public ReqResult sendCardSmsCode(CmccDaProduct cmccDaProduct, SendCodeDTO sendCodeDTO) {
        HashMap<String, Object> map = new HashMap<>(1 << 2);
        map.put("partnerId", interfaceParamsMap.get(SanJianKeChannelEnum.APP_ID.getName()));
        map.put("cardType",cmccDaProduct.getProductParam());
        map.put("certName",sendCodeDTO.getCertName());
        map.put("certNo", sendCodeDTO.getCertNum());
        map.put("contactNum", sendCodeDTO.getCustomerPhone());
        String sign = getSign(map, interfaceParamsMap.get(SanJianKeChannelEnum.APP_KEY.getName()));
        map.put("sign", sign);
        if ("1".equals(cmccDaProduct.getCodeFlag())) {
            map.put("code", sendCodeDTO.getCode());
        }
        String requestJson = new JSONObject(map).toString();
        JSONObject responseJson = JSONObject.parseObject(HttpRequestUtils.sendPost(SanJianKeChannelEnum.SEND_SMS.getName(), requestJson));
        if (!"0000".equals(responseJson.getString("result"))) {
            return ReqResult.error(responseJson.getString("info"));
        } else {
            return ReqResult.success(responseJson.getString("info"));
        }
    }


    @Override
    public RefreshOrderBO getRefreshOrderBO(CmccDaOrder cmccDaOrder) {
        // 三剑客是根据渠道方订单编号更新的
        List<CmccDaOrder> orderList = new ArrayList<>();
        orderList.add(cmccDaOrder);
        Map<CmccDaOrder,RefreshOrderBO> refreshOrderBOMap = getRefreshOrderBOList(orderList);
        return refreshOrderBOMap.isEmpty() ? null : refreshOrderBOMap.get(cmccDaOrder);
    }

    // 三剑客批量查单限制查询间隔1分钟，每次最多100条
    @Override
    public Map<CmccDaOrder,RefreshOrderBO> getRefreshOrderBOMap(List<CmccDaOrder> orderList) {
        return getRefreshOrderBOList(orderList);
    }

    private Map<CmccDaOrder,RefreshOrderBO> getRefreshOrderBOList(List<CmccDaOrder> orderList){
        List<CmccDaOrder> subList = orderList.subList(0, Math.min(100, orderList.size()));
        String orderIds = subList.stream().map(CmccDaOrder::getChannelOrderNo).collect(Collectors.joining(","));
        HashMap<String, Object> map = new HashMap<>(1 << 2);
        map.put("partnerId", interfaceParamsMap.get(SanJianKeChannelEnum.APP_ID.getName()));
        map.put("orderIds", orderIds);
        String sign = getSign(map, interfaceParamsMap.get(SanJianKeChannelEnum.APP_KEY.getName()));
        map.put("sign", sign);
        String requestJson = new JSONObject(map).toString();
        sjkOrderSearchLog.info("【三剑客】批量查单请求 => {}",requestJson);
        JSONObject responseJson = JSONObject.parseObject(HttpRequestUtils.sendPost(interfaceUrlsMap.get(SanJianKeChannelEnum.SELECT_ORDER.getName()), requestJson));
        sjkOrderSearchLog.info("【三剑客】批量查单响应 => {}",responseJson.toString());
        Map<CmccDaOrder,RefreshOrderBO> refreshOrderBOMap = new HashMap<>();
        if (!"0000".equals(responseJson.getString("result"))) {
            throw new ServiceException(responseJson.getString("info"));
        }
        // 成功
        JSONArray jsonArray = responseJson.getJSONObject("data").getJSONArray("list");
        if (!jsonArray.isEmpty()) {
            for (Object object : jsonArray) {
                JSONObject jsonObject = (JSONObject) object;
                RefreshOrderBO refreshOrderBO = new RefreshOrderBO();
                refreshOrderBO.setChannelOrderNo(jsonObject.getString("orderId"));// 渠道方订单号
                String productStatus = "-1";
                String status = "2";
                Integer state = jsonObject.getInteger("state");
                if (state == 6){
                    status = "3";
                    productStatus = "6";
                }else {
                    if (state == 4){
                        status = "-1";
                    }
                    if (state == 1){
                        productStatus = "1";
                    }
                    if (state == 10){
                        productStatus = "10";
                    }
                    if (state == 11){
                        productStatus = "11";
                    }
                }
                refreshOrderBO.setProductStatus(productStatus);// 卡状态
                refreshOrderBO.setStatus(status);// 状态 ：0=进行中，1=激活 4=失败 6=已完成/首充（该状态说明平台已结佣金） 10=开户 11=发货
                refreshOrderBO.setPhone(jsonObject.getString("number"));//订购号码
                refreshOrderBO.setStatusMsg(jsonObject.getString("info"));// 返回描述 （如：销户，首充不满足条件等）
                // 这里首冲金额单位是元，需要转换为分
                try {
                    String doMoney = String.valueOf(jsonObject.getBigDecimal("lgtsId"));
                    String s = StringUtils.isEmpty(doMoney) ? "0" : (new BigDecimal(doMoney).multiply(new BigDecimal(100))).toString();
                    refreshOrderBO.setScMoney(s);
                } catch (Exception e) {
                    log.error("渠道方订单编号为{}的订单刷新状态时首冲金额由元转换为分时出错，原因{}", refreshOrderBO.getOrderId(),e.getMessage());
                }
                refreshOrderBO.setCreateTime(jsonObject.getString("createtime")); // 更新时间
                // 激活时间（部分订单可能会返回空）
                refreshOrderBO.setLimitTime(jsonObject.getString("actime"));
                String logisticsInfo = StringUtils.isNotBlank(jsonObject.getString("wlCompany")) && StringUtils.isNotBlank(jsonObject.getString("wlOrderid")) ?
                        jsonObject.getString("wlCompany") + "-" + jsonObject.getString("wlOrderid") : "无";
                refreshOrderBO.setLogisticsInfo(logisticsInfo);// 物流信息
                CmccDaOrder cmccDaOrder = orderList.stream().filter(f -> StringUtils.equals(f.getChannelOrderNo(), refreshOrderBO.getChannelOrderNo())).collect(Collectors.toList()).get(0);
                refreshOrderBOMap.put(cmccDaOrder, refreshOrderBO);
            }
        }
        return refreshOrderBOMap;
    }

    /**
     * 获取签名信息
     *
     * @param map json map
     * @return 加密签名
     */
    private static String getSign(Map<String, Object> map, String appKey) {
        List<String> params = dictSort(map.keySet().toArray(new String[0]));
        StringBuilder stringBuffer = new StringBuilder();
        stringBuffer.append(appKey);
        for (String param : params) {
            stringBuffer.append(param).append(map.get(param));
        }
        stringBuffer.append(appKey);
        //System.out.println("三剑客签名好的参数：" + stringBuffer);
        return MD5Util.stringToMD5((stringBuffer.toString())).toUpperCase();
    }

    @Override
    public void refreshChannelCommission(CmccDaUpChannelInfo cmccDaUpChannelInfo) {
        // 登录
        Map<String, Object> loginParamMap = new HashMap<>();
        loginParamMap.put("account", cmccDaUpChannelInfo.getUserName());
        loginParamMap.put("password",cmccDaUpChannelInfo.getPassword());
        // 发送请求
        String requestJson = new JSONObject(loginParamMap).toString();
        String responseStr = HttpRequestUtils.sendPost(cmccDaUpChannelInfo.getLoginUrl(), requestJson);
        JSONObject responseJson = JSONObject.parseObject(responseStr);
        if (responseJson.getInteger("code") != 1) return;
        // 登录成功
        JSONObject userinfo = responseJson.getJSONObject("data").getJSONObject("userinfo");
        String token = userinfo.getString("token");
        // 配置登录参数
        Map<String, String> headerMap = new HashMap<>();
        headerMap.put("Token",token);
        // 发送请求
        String goodsInfoReturnStr = HttpRequestUtils.sendPostWithHeader(interfaceUrlsMap.get(SanJianKeChannelEnum.GET_GOODS_INFO.getName()),
                headerMap, null);
        JSONObject goodsInfoReturnJson = JSONObject.parseObject(goodsInfoReturnStr);
        if (goodsInfoReturnJson.getInteger("code") != 1) return;
        JSONArray goodsInfoJSONArray = goodsInfoReturnJson.getJSONObject("data").getJSONArray("list");
        Map<Integer,String> goodsIdCommissionMap = new HashMap<>();
        for (Object object : goodsInfoJSONArray) {
            JSONObject goodsInfoJson = (JSONObject) object;
            goodsIdCommissionMap.put(goodsInfoJson.getInteger("id"), goodsInfoJson.getString("agfee"));
        }
        updateChannelCommission(cmccDaUpChannelInfo, goodsIdCommissionMap);
    }
}
